#include <platform.h>
#include "protocmd.h"
#include "crc16.h"
#include "commbt.h"
#include "bluetooth_interface.h"


#define CMD_TCP			0x82
#define TCP_HEAD_TAG	0x50
#pragma pack(push)
#pragma pack(1)

#if 0
typedef struct {
	unsigned short SessionID, ReplyID;
}TSessionHeader, *PSessionHeader;
#endif

typedef struct {
	//HANDLE WaitTerminalRead;
	TSessionHeader sessionH;
	UDK_S32 SendBufferLen;
	UDK_U8 *SendBuffer;
	UDK_S32 RecvBufferLen;
	UDK_U8 *RecvBuffer;
} ST_COMMOBJ_BLUETOOTH, *PST_COMMOBJ_BLUETOOTH;

#pragma pack(pop)


//int LastError = 0;

UDK_HANDLE COMM_BLUETOOTH_INIT(PST_COMM_PARAMS param, const char *address, unsigned short PortNum, int speed)
{
	int ret = 0;
	ST_COMMOBJ_BLUETOOTH *h = (PST_COMMOBJ_BLUETOOTH)udk_malloc(sizeof(ST_COMMOBJ_BLUETOOTH));

	//UDK_LOGD( "COMM_BLUETOOTH_INIT....BTAddress:%s\n", address);
	/* In ZKBIOLOCK, Connection is established using ios native methods */
#ifndef ZKBIOLOCK   
	ret = BTInit(address);
#endif
	if (h)
	{
		memset(h, 0, sizeof(ST_COMMOBJ_BLUETOOTH));
		h->SendBufferLen = param->PackageSize + 16;
		h->SendBuffer = (UDK_U8*)udk_malloc(h->SendBufferLen);
		h->RecvBufferLen = param->PackageSize + 16;
		h->RecvBuffer = (UDK_U8*)udk_malloc(h->RecvBufferLen);
		//param->comm_obj = h;
	}
	
	return (UDK_HANDLE)h;
}

UDK_BOOL COMM_BLUETOOTH_CLOSE(UDK_HANDLE handle)
{
	ST_COMMOBJ_BLUETOOTH *h = (PST_COMMOBJ_BLUETOOTH)(handle);

#ifndef ZKBIOLOCK
	BTFree();
#endif

	if(h->SendBuffer)
		udk_free(h->SendBuffer);
	if(h->RecvBuffer)
		udk_free(h->RecvBuffer);
	if(h)
		udk_free(h);

	return UDK_TRUE;
}


int COMM_BLUETOOTH_SEND(UDK_HANDLE Handle,const char *Data, int Count)
{
    return 0;
}

int COMM_BLUETOOTH_READ(UDK_HANDLE Handle, char *Data, int Count, int TimeOutMS)
{
    return 0;
}


int COMM_BLUETOOTH_SENDCMD(UDK_HANDLE handle, int Command, char *Data, int Count, PSessionHeader pshd)
{
	ST_COMMOBJ_BLUETOOTH *h = (PST_COMMOBJ_BLUETOOTH)handle;
	PProtoHeader 		pchd = (PProtoHeader)(h->SendBuffer);
	UDK_S32 sendLen = sizeof(TProtoHeader) + CRC_AND_ENDTAG_LEN + Count,
			len = 0,
			sentLen = 0,
			byteSent = 0;
		
	UDK_U32 	msStartTime = 0, msCurrentTime = 0;
	UDK_U8 		*p;
	int TimeOutMS = 5000;

	UDK_LOGD("COMM_BLUETOOTH_SENDCMD start send\n");

	if(Count > h->SendBufferLen - 12)
	{
		return ERR_SEND_PACKAGE_BUF_INSUFFICIENT;
	}

	p = h->SendBuffer;
	pchd->StartTag = PROTO_START_TAG;
	pchd->DestAddr = 0x1;
	pchd->Command = Command & 0xff;
	pchd->DataSize = Count;
	//h->sessionH.ReplyID += 1;
	UDK_LOGD("COMM_BLUETOOTH_SENDCMD start, send Count=%d, h->SendBufferLen=%d, replayID:%d\n", 
											Count, h->SendBufferLen, h->sessionH.ReplyID);
	//fill session header
	if (pshd)
	{
		memcpy(pchd + 1, pshd, sizeof(TSessionHeader));	
		sendLen += sizeof(TSessionHeader);
		pchd->DataSize += sizeof(TSessionHeader);
		if (Count) 
			memcpy((char *)(p + sizeof(TProtoHeader) + sizeof(TSessionHeader)), Data, Count);		
	} else
	{
		if (Count)
			memcpy((char*)(p + sizeof(TProtoHeader)), Data, Count);
	}

	SETWORD(p + sizeof(TProtoHeader) + pchd->DataSize, crc16(p + 1, sendLen - sizeof(TSessionHeader)));

	*(p+sendLen - PROTOCOL_ENDTAG_LEN) = PROTO_END_TAG;

	len = sendLen;
	sentLen = 0;
	msStartTime = udk_get_ticks();
	while (sentLen < len)
	{
		msCurrentTime = udk_get_ticks();
		if ((msCurrentTime - msStartTime) > TimeOutMS)
		{
			UDK_LOGE("BLUETOOTH SEND timeout\n");
			break;
		}
		if (msCurrentTime < msStartTime)
		{
			UDK_LOGE("GetTickCount error\n");
			break;
		}
		//蓝牙4.0最大接收数据长度为20字节
        int nleft = len - sentLen;
        int maxsendLen = (nleft > 20) ? 20 : nleft;
		byteSent = BTWrite((char*)(h->SendBuffer + sentLen), 0, maxsendLen);
		byteSent = maxsendLen;
		UDK_LOGD("COMM_BLUETOOTH_SENDCMD start, byteSent=%d, replayID: %d\n", byteSent, h->sessionH.ReplyID);
		if (byteSent > 0)
		{
			sentLen += byteSent;
		} else if (byteSent == -2)
		{
			UDK_LOGE("Bluetooth connection lost, abort send\n");
			sentLen = ERR_CONN_LOST;	/* clear return value, void this operation */
			break;
		}
	}
	if (sentLen > 10)
	{
		udk_msleep(10);
	}
	//SetEvent(((PH)Handle)->WaitTerminalRead);
	UDK_LOGD("COMM_BLUETOOTH_SENDCMD finish, replayID:%d\n", h->sessionH.ReplyID);
	return sentLen;
}

int ClearBTData(void)
{
	int i = 0;
	int ret = 0;
	char buf[2*1024];

	for (i = 0; i < 30; i++)
	{
		if ((ret = BTSelect()) > 0) 
		{
			BTRead(buf, 0, sizeof(buf));
		}
	}

	return 1;
}

int COMM_BLUETOOTH_READCMD(UDK_HANDLE Handle,int *Command, char *Data, int *Count, int TimeOutMS)
{
	PST_COMMOBJ_BLUETOOTH 	h = (PST_COMMOBJ_BLUETOOTH)Handle;
	PProtoHeader			pchd = (PProtoHeader)h->RecvBuffer;
	int 			size = 0, c = 0;
	int				conn_lost = 0;	/* connection status */
	char 			*p = (char *)h->RecvBuffer;
	int 			dataBufInLen = *Count;

	int 			curLen = 0, len = 0;
	UDK_U32 		msStartTime = 0, msCurrentTime = 0;

	UDK_LOGD("COMM_BLUETOOTH_READCMD start read, buffersize=%d\n", *Count);
	msStartTime = udk_get_ticks();

	while(1)
	{
		msCurrentTime = udk_get_ticks();
		if ((msCurrentTime - msStartTime) > TimeOutMS)
		{
			break;
		}
		if (msCurrentTime < msStartTime)
		{
			UDK_LOGE("GetTickCount error\n");
			break;
		}
			//if(1/*BTSelect() > 0*/) 
		{
			curLen = 0;
			len = sizeof(TProtoHeader);

			while (curLen < len)
			{
				msCurrentTime= udk_get_ticks();
				if ((msCurrentTime - msStartTime) > TimeOutMS)
				{
					UDK_LOGW("Timeout occur\n");
					break;
				}
				if (msCurrentTime < msStartTime)
				{
					UDK_LOGE("GetTickCount error\n");
					break;
				}
				size = BTRead((char*)(h->RecvBuffer + curLen), 0, len - curLen); //最短命令至少8个字节
				if (size > 0) 
				{
                    curLen += size;
                } else if (size == -2) 	/* Bluetooth connection is lost, let's get out of here */
				{
					conn_lost = 1;
					break;
				}
			}
			if (curLen == sizeof(TProtoHeader) && pchd->StartTag == PROTO_START_TAG)
			{
				UDK_DUMP((const char *)"COMM_BLUETOOTH_READCMD", (const char *)h->RecvBuffer, curLen);
				UDK_LOGD("BTRead, sizeof(TProtoHeader)=%d, size=%d, %02x %02x %02x %02x %02x\n", 
																sizeof(TProtoHeader), curLen, 
																(unsigned char )p[0], (unsigned char )p[1], 
																(unsigned char )p[2], (unsigned char )p[3], 
																(unsigned char )p[4]);
			} else if (conn_lost)
			{
				UDK_LOGE("Bluetooth connection lost, no need going down\n");
				len = ERR_CONN_LOST;	/* set return value */
				break;
			}
			else if (!curLen)
			{
				UDK_LOGE("Bluetooth read timeout, returning\n");	/* mostly */
				break;
			} else 
            {
                UDK_LOGE("Bluetooth read headlen incomplete, returnning");
                break;
            }

			if (curLen == sizeof(TProtoHeader) && pchd->StartTag == PROTO_START_TAG)
            {
                //curLen = size;
                len = sizeof(TProtoHeader) + pchd->DataSize + 3;
                UDK_LOGE("read data len=%d, recvBufLen=%d\n", len, h->RecvBufferLen);

                if (len > h->RecvBufferLen)
                {
                    len = ERR_READ_PACKAGE_BUF_INSUFFICIENT;
                    break;
                }
                while (curLen < len)
                {
                    msCurrentTime = udk_get_ticks();
                    if ((msCurrentTime - msStartTime) > TimeOutMS)
                    {
						UDK_LOGW("Timeout occur\n");
                        break;
                    }
                    if (msCurrentTime < msStartTime)
                    {
                        UDK_LOGE("GetTickCount error\n");
                        break;
                    }
                    size = BTRead((char*)(h->RecvBuffer + curLen), 0, len - curLen);				 
                    if (size > 0)
                    {
						UDK_LOGD("Reading %d bytes from bt, actual read: %d bytes\n", len - curLen, size);
                        curLen += size;
                        //printf("curlen %d\n",curlen);
                    } else if (size == -2) 
					{
						conn_lost = 1;
						break;
					}
                    else
                    {
                        if (errno == EAGAIN)
                            continue;
                        else
                        {
                            //printf("recv error %s\n",strerror(errno));
                            //LastError = errno;
							//break;
							continue;
                        }
                    }
                }

				if (conn_lost) 
				{
					UDK_LOGE("Bluetooth connection lost, stop process.\n");
					len = ERR_CONN_LOST;	/* set return value */
					break;
				}
                if (curLen == len)
                {
                    //校验收到数据的完整性
                    UDK_U16 crc16r = GETWORD(p + len - 3);
                    UDK_U16 crc16l = crc16((UDK_U8 *)(p + 1), len - 4);
                    if (crc16r == crc16l)
                    {
                        *Command = pchd->Command;
                        if (pchd->DataSize <= dataBufInLen) 
						{
                           *Count = pchd->DataSize;
                           memcpy(Data, pchd + 1, pchd->DataSize);	//data stored error code darcy20110315
                           //memcpy(&(h->sessionH), p+sizeof(TProtoHeader), 4);
                           //memcpy(Data,p+sizeof(TProtoHeader) + 4, pchd->DataSize - 4);
                        } else if (dataBufInLen > 0) 
						{
                            /* out of memory */
                            *Count = ERR_READ_BUF_INSUFFICIENT;
                        }
                    } else
                    {
                        UDK_LOGE("COMM_BLUETOOTH_READCMD data crc error\n");
                        //ClearBTData();	//add by zuocs
                        len = ERR_CMD_DATA_CRC_ERROR;
                        BTClear();
                        //SetEvent(h->WaitActive);
                    }
                }
                else
                {
                    BTClear();
                    len = ERR_CMD_DATA_LEN_ERROR;
                }
            } else if (size == sizeof(TProtoHeader))
			{
                BTClear();
                len = 0;
				//ClearBTData();		//add by zuocs
			}
			else
			{
                BTClear();
				len = 0;
			}

			break;
		}
		udk_msleep(1);
	}
	UDK_LOGD("COMM_BLUETOOTH_READCMD finish, len=%d, replayID:%d\n", len, h->sessionH.ReplyID);

	return curLen;	//modify by 20150901
}


int COMM_BLUETOOTH_PREREAD(UDK_HANDLE Handle)
{
	return COMM_BLUETOOTH_READ(Handle, NULL, 0, 0);
}

int COMM_BLUETOOTH_TERMINALREAD(UDK_HANDLE Handle)
{
	return 0;//SetEvent(((PH)Handle)->WaitTerminalRead);
}

const char* COMM_BLUETOOTH_NAME(UDK_HANDLE Handle)
{
	return (const char*)"BLUETOOTH";
}

int COMM_BLUETOOTH_ERROR(UDK_HANDLE Handle)
{
	return -1;//LastError;
}

#ifdef COMM_MODULE_AUTOINSTALL
class CCommModuleBT
{
	public:

		CCommModuleBT()
		{
            UDK_LOGI("CCommModuleBT install\n");
			selfInstall();
		}
		virtual ~CCommModuleBT()
		{
		  uninstall_comm_module((const char*)"BLUETOOTH");
		}
		void selfInstall(void)
		{
			ST_COMM_MODULE my_comm=
			{
					"BLUETOOTH",//prot
					"plbtcomm",//libraryname
					COMM_BLUETOOTH_INIT,//init
					COMM_BLUETOOTH_CLOSE,//close
					COMM_BLUETOOTH_SEND,//send
					COMM_BLUETOOTH_READ,//read
					COMM_BLUETOOTH_TERMINALREAD,//terminalread
					COMM_BLUETOOTH_NAME,//name
					NULL,//flush
					NULL,//at->modem
					NULL,//at<-modem		
					NULL,//error
					COMM_BLUETOOTH_SENDCMD,//sendcmd
					COMM_BLUETOOTH_READCMD,//readcmd
			};
			install_comm_module(&my_comm);
		}

};
static CCommModuleBT comminstance;
#endif
